<?php

namespace App\Repositories;

use App\Enums\RedisKeyEnum;
use App\Enums\CrossRoomPkEnum;
use App\Services\Tools\PushService;
use App\Services\Tools\RedisService;
use App\Services\Tools\CommonService;

class CrossRoomPkRepository
{
    /**
     * @Desc: 跨房PK列表
     * @param $param
     * @param $page
     * @param $perPage
     * @return mixed
     * @author: shiquan
     * @Time: 2022/9/19 16:06
     */
    public function list($param, $page = 1, $perPage = 10)
    {
        $time = CommonService::transTime($param['start_at'], $param['end_at']);

        $list = app('model_cross_room_pk')->from('ln_cross_room_pk as p')->join('ln_user_room as r','p.room_id','=','r.id')->with('room:id,room_id,room_name');

        $list->whereBetween('p.end_time', [$time['start_at'], $time['end_at']]);

        if (isset($param['win_flag']) && !empty($param['win_flag'])) {
            $list = $list->where('p.win_flag', $param['win_flag']);
        } else {
            $list = $list->where('p.win_flag', '>', 0);
        }
        //按发起者房间名/ID查询

        if (isset($param['search']) && !empty($param['search'])) {
            $search = $param['search'];
            if (is_numeric($search)){
                $search = app('model_user_room')->select('id')->where('room_id', $search)->first()['id'] ?? 0;
            }
            //按发起者房间名/ID查询
            //or查询
            $list = $list->where(function ($query) use ($search) {
                if (is_numeric($search)){
                    $query->where('p.room_id', $search);
                } else {
                    $query->Where('p.room_name', 'like', "%{$search}%");
                }
            });
        }
        //按接收者发起者房间名/ID查询

        if (isset($param['meet_search']) && !empty($param['meet_search'])) {
            $search = $param['meet_search'];
            if (is_numeric($search)){
                $search = app('model_user_room')->select('id')->where('room_id', $search)->first()['id'] ?? 0;
            }
            //按发起者房间名/ID查询
            //or查询
            $list = $list->where(function ($query) use ($search) {
                if (is_numeric($search)){
                    $query->where('p.meet_room_id', $search);
                } else {
                    $query->Where('p.meet_room_name', 'like', "%{$search}%");
                }
            });
        }

        $list = $list->select(
            'p.id',
            'r.room_id',
            'p.room_name',
            'p.user_id',
            'p.user_voice_status',
            'p.meet_room_id',
            'p.meet_user_id',
            'p.meet_room_name',
            'p.meet_voice_status',
            'p.start_time',
            'p.real_end_time',
            'p.duration',
            'p.user_charm',
            'p.meet_user_charm',
            'p.win_flag',
            'p.status',
            'p.abnormal_status'
        )->orderBy('id', 'desc')->paginate($perPage, ['*'], '', $page);

        foreach ($list as &$val) {
            $val->duration_string = self::changeTime($val->duration);
            $val->win_flag_string = self::changeWinFlag($val->win_flag, $val->room_name, $val->meet_room_name);
            $val->end_time_string = !empty($val->real_end_time) ? date('Y-m-d H:i:s', $val->real_end_time) : '';
            $val->meet_room_name = $val->room->room_name;
            $val->meet_room_id = $val->room->room_id;
        }
        return $list;
    }

    /**
     * @Desc:   详情
     * @param $id
     * @return mixed
     * @author: shiquan
     * @Time: 2022/9/19 16:08
     */
    public function info($id)
    {
        $info = app('model_cross_room_pk')->where('id', $id)->first()->toArray();
        $users = [
            $info['user_id'], $info['meet_user_id']
        ];
        $sociatyUser = app('model_sc_sociaty_user')->whereIn('user_id', $users)->with('sociaty:id,sociaty_name')->get()->toArray();
        $info['sociaty_name'] = '';         //发起房间的公会信息
        $info['meet_sociaty_name'] = '';    //受邀房间的公会信息
        foreach ($sociatyUser as $value){
            if ($value['user_id'] == $info['user_id']){
                $info['sociaty_name'] = $value['sociaty']['sociaty_name'];
            } elseif ($value['user_id'] == $info['meet_user_id']) {
                $info['meet_sociaty_name'] = $value['sociaty']['sociaty_name'];
            }
        }
        $info['duration_string'] = self::changeTime($info['duration']);
        $info['initiator_pk_win_flag'] = self::infoWinFlag($info['win_flag']);
        $info['meet_pk_win_flag'] = self::infoWinFlag($info['win_flag'], 2);
        if ($info['status'] == CrossRoomPkEnum::CROSS_ABNORMAL){
            $info['abnormal_status_string'] = self::abnormalStatusReplace($info['abnormal_status']);
            //还要告诉前端是哪个房间异常 abnormal_room_id
            if ($info['room_id'] == $info['abnormal_room_id']){
                $info['left_room_abnormal'] = 1;      //1代表异常
                $info['right_room_abnormal'] = 0;
            } else {
                $info['left_room_abnormal'] = 0;
                $info['right_room_abnormal'] = 1;
            }
        } else {
            $info['left_room_abnormal'] = 0;
            $info['abnormal_status_string'] = '';
            $info['right_room_abnormal'] = 0;
        }
        $info['room_id'] = app('model_user_room')->select('room_id')->where('id', $info['room_id'])->first()['room_id'] ?? 0;
        $info['meet_room_id'] = app('model_user_room')->select('room_id')->where('id', $info['meet_room_id'])->first()['room_id'] ?? 0;
        $info['user_id'] = RedisService::getUserBaseInfo($info['user_id'])['user_code'] ?? '';//展示需要是code
        $info['meet_user_id'] = RedisService::getUserBaseInfo($info['meet_user_id'])['user_code'] ?? '';
        return $info;
    }

    /**
     * @Desc:将秒转化为时分秒
     * @param $second
     * @return mixed|string
     * @author: shiquan
     * @Time: 2022/9/20 10:12
     */
    public static function changeTime($second)
    {
        if ($second == 0) return $second;
        $hour = floor($second / 3600);
        $minute = floor(($second - 3600 * $hour) / 60);
        $second = floor((($second - 3600 * $hour) - 60 * $minute) % 60);

        if ($hour > 0) {
            $hour = $hour. '小时';
        } else {
            $hour = '';
        }

        if ($minute > 0) {
            $minute = $minute. '分钟';
        } else {
            $minute = '';
        }

        if ($second < 10 && $second > 0) {
            $second = '0'. $second. '秒';
        } elseif ($second >= 10) {
            $second = $second . '秒';
        } else {
            $second = '';
        }

        $newTime = $hour. $minute . $second;
        return $newTime;
    }

    /**
     * @Desc:将PK结果转化为字符串
     * @param $winFlag  //PK状态
     * @param $roomName //左方房间名
     * @param $meetRoomName //右方房间名
     * @return string
     * @author: shiquan
     * @Time: 2022/9/20 10:13
     */
    public static function changeWinFlag($winFlag, $roomName, $meetRoomName)
    {
        switch ($winFlag){
            case 0:
                $string = '正在PK中';
                break;
            case 1:
                $string = $roomName. '胜利,'. $meetRoomName. '失败';
                break;
            case 2:
                $string = $meetRoomName. '胜利,'. $roomName. '失败';
                break;
            case 3:
                $string = '平局';
                break;
            default:
                $string = '流局';
                break;
        }
        return  $string;
    }

    /**
     * @Desc:详情将PK结果转化为字符串
     * @param $winFlag  //PK结果
     * @param $type     //类型 1 : 发起方; 2 : 接受方
     * @return string
     * @author: shiquan
     * @Time: 2022/9/20 14:13
     */
    public static function infoWinFlag($winFlag, $type = 1)
    {
        switch ($winFlag){
            case 0:
                $string = '正在PK中';
                break;
            case 1:
                $string = $type == 1 ? '胜利' : '失败';
                break;
            case 2:
                $string = $type == 1 ? '失败' : '胜利';
                break;
            case 3:
                $string = '平局';
                break;
            default:
                $string = '流局';
                break;
        }
        return  $string;
    }

    /**
     * @Desc:PK房异常处理
     * @param $roomId
     * @param $abnormaStatus
     * @param $type
     * @author: shiquan
     * @Time: 2022/10/15 16:15
     */
    public function abnormaHandle($roomId, $abnormaStatus)
    {
        \DB::beginTransaction();
        //根据房间ID查询出正在PK中的房间,应该只有一条数据
        $pkRoomInfo = app('model_cross_room_pk')->where('status', CrossRoomPkEnum::CROSS_CONDUCT)
            ->where(function ($query) use ($roomId) {
                $query->where('room_id', $roomId)->orWhere('meet_room_id', $roomId);
            })->latest('id')->first();
        if (empty($pkRoomInfo)) {
            \DB::commit();
            return;
        }
        $pkId = $pkRoomInfo['id'];
        //先将redis的数据更新到库
        $this->updatePkValueById($pkId);
        $pkRoomInfo = app('model_cross_room_pk')->where('id', $pkId)->lockForUpdate()->first();
        if ($pkRoomInfo['status'] != CrossRoomPkEnum::CROSS_CONDUCT){
            \DB::commit();
            return;
        }
        //需要获取下该房间是发起方还是接收方,并判断是哪个房间异常了
        $abnormalRoomId = $roomId;
        if ($pkRoomInfo['room_id'] == $roomId) {
            //说明是发起方的问题
            $roomMsg = self::abnormalStatusReplace($abnormaStatus);
            $meetRoomMsg = '';
        } else {
            $roomMsg = '';
            $meetRoomMsg = self::abnormalStatusReplace($abnormaStatus);
        }

        //更新统计数据
        $data['abnormal_status'] = $abnormaStatus;
        $data['abnormal_room_id'] = $abnormalRoomId;
        if ($abnormaStatus == CrossRoomPkEnum::ABNORMAL_DEFAULT){
            $data['status'] = CrossRoomPkEnum::CROSS_END;
        } else {
            $data['status'] = CrossRoomPkEnum::CROSS_ABNORMAL;
        }
        $data['real_end_time'] = time();
        if (!empty($pkRoomInfo['start_time'])){ //有开始时间才能有时长
            $data['duration'] = time() - $pkRoomInfo['start_time'];
        }
        $data['win_flag'] = $this->winFlag($pkRoomInfo);
        $where = ['id' => $pkRoomInfo['id']];

        //异常发消息 //需要的参数.房间名+状态+PK值+我方前三
        /**
         * 处理发起方 begin
         */
        $roomName = $pkRoomInfo['room_name'];
        $roomStatus = $data['win_flag'];        //对于发起方.不需要改变
        $userCharm = intval($pkRoomInfo['user_charm']);
        $topThreeContributeList = $this->topThreeContributeList($pkRoomInfo['id'], $pkRoomInfo['room_id']);
        $userContributeList = [];
        if (!empty($topThreeContributeList)){
            foreach ($topThreeContributeList as $key => $value){
                $userInfo = RedisService::getUserBaseInfo($value['pit_user_id']);
                $userContributeList[] = [
                    'head_picture' => $userInfo['head_picture'] ?? '',
                    'user_charm' => intval($value['value'])
                ];
            }
        }
        /**
         * 处理发起方 end
         */
        /**
         * 处理接受方 begin
         */
        $meetRoomName = $pkRoomInfo['meet_room_name'];
        if ($data['win_flag'] == CrossRoomPkEnum::WIN_FLAG_LEFT){
            $meetRoomStatus = CrossRoomPkEnum::WIN_FLAG_RIGHT;       //接收方要换下参数
        } elseif($data['win_flag'] == CrossRoomPkEnum::WIN_FLAG_RIGHT){
            $meetRoomStatus = CrossRoomPkEnum::WIN_FLAG_LEFT;
        } else {
            $meetRoomStatus = $data['win_flag'];
        }
        $meetUserCharm = intval($pkRoomInfo['meet_user_charm']);
        $meetTopThreeContributeList = $this->topThreeContributeList($pkRoomInfo['id'], $pkRoomInfo['meet_room_id']);
        $meetUserContributeList = [];
        if (!empty($meetTopThreeContributeList)){
            foreach ($meetTopThreeContributeList as $key => $value){
                $userInfo = RedisService::getUserBaseInfo($value['pit_user_id']);
                $meetUserContributeList[] = [
                    'head_picture' => $userInfo['head_picture'] ?? '',
                    'user_charm' => intval($value['value'])
                ];
            }
        }
        /**
         * 处理接受方 end
         */

        //对于异常的结束,谁异常,那么谁失败
        if ($data['status'] == CrossRoomPkEnum::CROSS_ABNORMAL){
            if ($pkRoomInfo['room_id'] == $roomId){
                $roomStatus = CrossRoomPkEnum::WIN_FLAG_ABNL;
                $meetRoomStatus = CrossRoomPkEnum::WIN_FLAG_LEFT;
                $data['win_flag'] = CrossRoomPkEnum::WIN_FLAG_RIGHT;
            } else {
                $roomStatus = CrossRoomPkEnum::WIN_FLAG_LEFT;
                $meetRoomStatus = CrossRoomPkEnum::WIN_FLAG_ABNL;
                $data['win_flag'] = CrossRoomPkEnum::WIN_FLAG_LEFT;
            }
        }

        //更新数据
        app('model_cross_room_pk')->where($where)->update($data);

        //只有胜利方才会加入排行榜
        if ($roomStatus == CrossRoomPkEnum::WIN_FLAG_LEFT){
            $this->addActivityData($pkId, $pkRoomInfo['room_id']);
        } elseif ($meetRoomStatus == CrossRoomPkEnum::WIN_FLAG_LEFT) {
            $this->addActivityData($pkId, $pkRoomInfo['meet_room_id']);
        }

        //只要发起过PK的,都会累计到房间PK中
        $this->addActivityRoomData($pkRoomInfo);

        //发起方
        $this->receiveAbnormalPush($pkRoomInfo['room_id'], $roomName, $abnormaStatus, $roomMsg, $roomStatus, $userCharm, $userContributeList);
        //接受方
        $this->receiveAbnormalPush($pkRoomInfo['meet_room_id'], $meetRoomName, $abnormaStatus, $meetRoomMsg, $meetRoomStatus, $meetUserCharm, $meetUserContributeList);

        $roomKey = sprintf(RedisKeyEnum::CONFIG_PK_ROOM_INFO, $pkRoomInfo['room_id']);
        $meetRoomKey = sprintf(RedisKeyEnum::CONFIG_PK_ROOM_INFO, $pkRoomInfo['meet_room_id']);
        app('redis')->del($roomKey);
        app('redis')->del($meetRoomKey);
        \DB::commit();
        return true;

    }

    /**
     * @Desc:计算出PK值
     * @param $pkId
     * @return bool
     * @author: shiquan
     * @Time: 2022/10/18 17:22
     */
    public function updatePkValueById($pkId)
    {
        $redis = app('redis');
        $PkValueKey = sprintf(RedisKeyEnum::CROSS_PK_ROOM_VALUE,$pkId);
        $leftValue = $redis->hget($PkValueKey,'left') ?? 0;
        $rightValue = $redis->hget($PkValueKey,'right') ?? 0;
        $update = [];
        if ($leftValue > 0){
            $update['user_charm'] = $leftValue;
        }
        if ($rightValue > 0){
            $update['meet_user_charm'] = $rightValue;
        }
        if (!empty($update)){
            app('model_cross_room_pk')->where('id',$pkId)->update($update);
        }
        return true;
    }

    /**
     * @Desc:异常转化为字符串
     * @param $status
     * @return string
     * @author: shiquan
     * @Time: 2022/10/15 16:22
     */
    public static function abnormalStatusReplace($status)
    {
        switch ($status){
            case 0:
                $string = '';
                break;
            case 1:
                $string = '因房间切换为其他房间模式';
                break;
            case 2:
                $string = '因房间被封禁';
                break;
            case 3:
                $string = '因房主主动结束PK';
                break;
            case 4:
                $string = '因主持麦被封禁';
                break;
            case 5:
                $string = '因主持麦退出房间';
                break;
            case 6:
                $string = '因主持麦下麦';
                break;
            case 7:
                $string = '因主持麦弱网至被踢出房间';
                break;
            case 8:
                $string = '因主持麦主动结束PK';
                break;
            case 100:
                $string = '未知';
                break;
        }
        return $string ?? '未知';
    }

    /**
     * @Desc:输赢转换
     * @param $roomPk
     * @return int
     * @author: shiquan
     * @Time: 2022/10/15 16:22
     */
    public function winFlag($roomPk)
    {
        $winFlag = 0;
        if ($roomPk['user_charm'] > $roomPk['meet_user_charm']) {
            $winFlag = CrossRoomPkEnum::WIN_FLAG_LEFT;
        }
        if ($roomPk['user_charm'] < $roomPk['meet_user_charm']) {
            $winFlag = CrossRoomPkEnum::WIN_FLAG_RIGHT;
        }
        if ($roomPk['user_charm'] == $roomPk['meet_user_charm']) {
            $winFlag = CrossRoomPkEnum::WIN_FLAG_FLAT;
        }

        return $winFlag;
    }

    /**
     * @Desc:获取前三列表
     * @param $pkId
     * @param $roomId
     * @return mixed
     * @author: shiquan
     * @Time: 2022/10/15 16:22
     */
    public function topThreeContributeList($pkId, $roomId)
    {
        $topThreeList = app('model_cross_room_pk_contribute')->selectRaw('pit_user_id, SUM(value) as value')
            ->where(['pk_id' => $pkId, 'room_id' => $roomId])->where('value', '>', 0)->groupBy('pit_user_id')->orderBy('value', 'desc')->limit(3)->get()->toArray();
        return $topThreeList;
    }

    /**
     * @Desc:异常行为结束和普通结束都是走这个推送
     * @param $roomId
     * @param $meetRoomId
     * @param $abnormalStatus
     * @param $roomMsg
     * @param $abnormalRoomId
     * @return bool
     * @author: shiquan
     * @Time: 2022/10/14 11:02
     */
    public function receiveAbnormalPush($roomId, $roomName, $abnormaStatus, $roomMsg, $roomStatus, $userCharm, $userContributeList)
    {
        $data = [
            'room_id'         => $roomId,               //初始时的发起方
            'room_name'         => $roomName,           //初始时的发起方
            'abnormal_status' => $abnormaStatus,        //异常信息状态
            'status' => $roomStatus,                     //1=胜利;2=平局;3=失败
            'user_charm' => $userCharm,                    //PK值
            'user_contribute_list' => $userContributeList, //贡献前三
            'msg' => $roomMsg,                              //异常信息
        ];
        (new PushService(0, $roomId))->abnormalEnd($data);
        return true;
    }

    /**
     * @Desc:加入数据
     * @param $pkId
     * @param $roomId
     * @param $charm
     * @return bool
     * @author: shiquan
     * @Time: 2022/10/18 10:48
     */
    public function addActivityData($pkId, $roomId)
    {
        if ($this->checkTimeRange()){
            //判断是否存在PK值大于10000的
            $pkContributeList = app('model_cross_room_pk_pit_contribute')->selectRaw('pit_user_id, SUM(value) as value')->where([
                'pk_id' => $pkId,
                'room_id' => $roomId
            ])->where('value', '>=', 10000)->groupBy('pit_user_id')->orderBy('value', 'desc')->get()->toArray();

            if (!empty($pkContributeList)){
                $maxValue = 0;
                $insertUserRankData = [];
                $i = 0;
                $time = date('Y-m-d H:i:s');
                foreach ($pkContributeList as $key => $value){
                    if ($key == 0){
                        $maxValue = $value['value'];
                        $insertUserRankData[$i]['pk_id'] = $pkId;
                        $insertUserRankData[$i]['room_id'] = $roomId;
                        $insertUserRankData[$i]['user_id'] = $value['pit_user_id'];
                        $insertUserRankData[$i]['created_at'] = $time;
                        $insertUserRankData[$i]['updated_at'] = $time;
                    } else {
                        if ($value['value'] >= $maxValue){
                            $i++;
                            $insertUserRankData[$i]['pk_id'] = $pkId;
                            $insertUserRankData[$i]['room_id'] = $roomId;
                            $insertUserRankData[$i]['user_id'] = $value['pit_user_id'];
                            $insertUserRankData[$i]['created_at'] = $time;
                            $insertUserRankData[$i]['updated_at'] = $time;
                        }
                    }
                }
                if (!empty($insertUserRankData)){
                    app('model_cross_room_user_rank')->insert($insertUserRankData);
                }
            }
        }
        return true;
    }

    /**
     * @Desc:加入房间排行数据
     * @param $pkRoomInfo
     * @return bool
     * @author: shiquan
     * @Time: 2022/10/26 14:36
     */
    public function addActivityRoomData($pkRoomInfo)
    {
        if ($this->checkTimeRange()){

            $insertRankData = [
                'room_id' => $pkRoomInfo['room_id'],
                'charm' => $pkRoomInfo['user_charm'],
                'user_id' => $pkRoomInfo['user_id']
            ];

            $insertMeetRankData = [
                'room_id' => $pkRoomInfo['meet_room_id'],
                'charm' => $pkRoomInfo['meet_user_charm'],
                'user_id' => $pkRoomInfo['meet_user_id']
            ];

            if (app('model_cross_room_pk_rank')->where('room_id', $pkRoomInfo['room_id'])->first()){
                app('model_cross_room_pk_rank')->where('room_id', $pkRoomInfo['room_id'])->increment('charm', $pkRoomInfo['user_charm']);
            } else {
                app('model_cross_room_pk_rank')->create($insertRankData);
            }
            if (app('model_cross_room_pk_rank')->where('room_id', $pkRoomInfo['meet_room_id'])->first()){
                app('model_cross_room_pk_rank')->where('room_id', $pkRoomInfo['meet_room_id'])->increment('charm', $pkRoomInfo['meet_user_charm']);
            } else {
                app('model_cross_room_pk_rank')->create($insertMeetRankData);
            }
        }
        return true;
    }

    /**
     * @Desc:检查时间
     * @return bool
     * @author: shiquan
     * @Time: 2022/10/12 10:50
     */
    public function checkTimeRange()
    {
        $config = $this->getConfig();
        $now = date('Y-m-d H:i:s');
        return ($now >= $config['start_time'] && $now <= $config['end_time']);
    }

    /**
     * @Desc:获取配置
     * @return array|mixed
     * @author: shiquan
     * @Time: 2022/10/12 10:50
     */
    public function getConfig()
    {
        $config = app('model_config')->getValue('CROSS_ROOM_PK_CONFIG');
        $limit = json_decode($config,true,512,JSON_UNESCAPED_UNICODE);
        return $limit ?? [];
    }

}
